﻿Public Class DonemBox : Inherits ComboBox

	Public MinDonem As String = ""
	Public MaxDonem As String = ""

	Dim WithEvents Donem As New TextBox
	Dim WithEvents Yil As New TextBox

	Sub New()
		MyBase.New()
		SmartFormatting = True
		List = False
		Donem.Width = 16
		Donem.MaxLength = 2
		Donem.AllowOnlyNumeric = True
		Yil.Width = 32
		Yil.MaxLength = 4
		Yil.AllowOnlyNumeric = True
		Controls.Add(Donem)
		Controls.Add(Yil)
		Donem.BackColor = Color.Red
		Yil.BackColor = Color.Red
		Donem.Location = New Point(4, 0)
		Donem.TextAlign = HorizontalAlignment.Center
		Yil.Location = New Point(28, 0)
		Yil.TextAlign = HorizontalAlignment.Center
	End Sub

	Protected Overrides Sub OnPaint(e As System.Windows.Forms.PaintEventArgs)
		MyBase.OnPaint(e)
		Dim R As New Rectangle(Donem.Right + 1, 0, Yil.Left - Donem.Right - 2, Height)
		R.Inflate(-1, 0)
		e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
		e.Graphics.DrawLine(Color.Black.Opacity(64).Pen, R.Left, R.Bottom, R.Right, R.Top)
	End Sub

	Public Overrides Property Value() As Object
		Get
			If Yil Is Nothing Then Return ""
			Dim t = Yil.Value & Donem.Value
			If Not IsDonem(t) Then Return DBNull.Value
			Return t
		End Get
		Set(ByVal Value As Object)
			If IsDBNull(Value) Then Value = ""
			If IsDonem(Value) Then
				Normalize(Value)
				If Isveren Then
					Donem.Value = Mid(Value, 5, 1)
					Yil.Value = Mid(Value, 1, 4)
				Else
					Donem.Value = Mid(Value, 5, 2)
					Yil.Value = Mid(Value, 1, 4)
				End If
			Else
				Donem.Value = ""
				Yil.Value = ""
			End If
		End Set
	End Property

	Dim _Isveren As Boolean
	Property Isveren As Boolean
		Get
			Return _Isveren
		End Get
		Set(value As Boolean)
			_Isveren = value
			If value Then
				MinDonem = "19771"
				MaxDonem = Today.AddMonths(-3).Year & Int(((Today.AddMonths(-3).Month - 1) / 3) + 1)
				Donem.MaxLength = 1
			Else
				MinDonem = "197701"
				MaxDonem = Today.YM
				Donem.MaxLength = 2
			End If
		End Set
	End Property

	Public Overrides Sub OnUpDownButtonClicked(e As System.Windows.Forms.MouseEventArgs, inc As Integer)
		MyBase.OnUpDownButtonClicked(e, inc)
		If IsNull(Value, "") = "" Then Value = MaxDonem : Return
		Dim d As New Date(Mid(Value, 1, 4), Mid(Value, 5, 2), 1)
		d = d.AddMonths(inc)
		Value = d.YM
	End Sub

	Private Sub DateBox_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.TextChanged
		RaiseChangeEvent()
	End Sub

	Protected Overrides Sub OnValidating(e As System.ComponentModel.CancelEventArgs)
		MyBase.OnValidating(e)
		Dim ay = Text.Right(2).Replace("_", "")
		If ay.Length = 1 Then
			Text = Text.Left(4) & "/0" & ay
		End If
	End Sub

	Public Overrides ReadOnly Property IsEmpty() As Boolean
		Get
			Return Trim(Donem.Text) & Trim(Yil.Text) = ""
		End Get
	End Property

	ReadOnly Property IsValid() As Boolean
		Get
			Return IsDonem(Yil.Text & Donem.Text)
		End Get
	End Property

	Public Overrides Function Errors() As String
		If IsRequired AndAlso IsEmpty Then Return Caption & " alanı boş olamaz."
		If Not IsEmpty AndAlso Not IsValid Then Return Caption & " alanı geçersiz bir tarih içeriyor."
		Return ""
	End Function

	Public Overrides Function GetDropDownControl() As System.Windows.Forms.Control
		Dim Calendar As New DonemCalendar(Me)
		If Not IsDBNull(Value) Then Calendar.Value = Value
		AddHandler Calendar.DateSelected, AddressOf SelectDate
		Return Calendar
	End Function

	Sub SelectDate(sender As Object)
		Value = sender.Value
		CloseMenu()
		RaiseChangeEvent()
	End Sub

	Public Overrides Sub Reset()
		MyBase.Reset()
		Value = [Default]
	End Sub

	Private Function IsDonem(Text As String) As Boolean
		If Not (Text.Left(4) >= "0000" And Text.Left(4) <= "9999") Then Return False
		If Isveren Then
			If Text.Length <> 5 Then Return False
			If Not (Text.Right(1) >= "1" And Text.Right(2) <= "4") Then Return False
		Else
			If Text.Length <> 6 Then Return False
			If Not (Text.Right(2) >= "01" And Text.Right(2) <= "12") Then Return False
		End If
		Return True
	End Function

	Sub Normalize(ByRef Value As String)
		If Value < MinDonem Then Value = MinDonem
		If Value > MaxDonem Then Value = MaxDonem
	End Sub

	Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message, keyData As System.Windows.Forms.Keys) As Boolean
		If keyData = Keys.Add Then
			Dim a = IsNull(Value, MaxDonem)
			Normalize(a)
			If Isveren Then
				Dim y = Mid(a, 1, 4) : Dim d = Mid(a, 5, 1)
				Value = If(d = 4, (y + 1) & "1", y & (d + 1))
				Return True
			Else
				Dim d As New Date(Mid(a, 1, 4), Mid(a, 5, 2), 1)
				Value = d.AddMonths(+1).YM
				Return True
			End If
		ElseIf keyData = Keys.Subtract Then
			Dim a = IsNull(Value, MinDonem)
			Normalize(a)
			If Isveren Then
				Dim y = Mid(a, 1, 4) : Dim d = Mid(a, 5, 1)
				Value = If(d = 1, (y - 1) & "4", y & (d - 1))
				Return True
			Else
				Dim d As New Date(Mid(a, 1, 4), Mid(a, 5, 2), 1)
				Value = d.AddMonths(-1).YM
				Return True
			End If
		End If
		Return MyBase.ProcessCmdKey(msg, keyData)
	End Function

	Private Sub Donem_TextChanged(sender As Object, e As System.EventArgs) Handles Donem.TextChanged, Yil.TextChanged
		MyBase.RaiseChangeEvent()
	End Sub

	Private Sub Donem_Validating(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles Donem.Validating
		If Len(Donem.Value) = 1 And Not Isveren Then Donem.Value = "0" & Donem.Value
	End Sub
End Class

Public Class DonemCalendar : Inherits UserControl
	Dim th As Integer = 24
	Dim w As Integer = 45
	Dim h As Integer = 30
	Dim DonemBox As DonemBox

	Sub New(Parent As DonemBox)
		Me.DonemBox = Parent
		DoubleBuffered = True
		MinimumSize = New Size(0, 0)
		MaximumSize = New Size(0, 0)
		MinimumSize = New Size((w + 1) * 3 - 2, th + (h + 1) * 4)
		MaximumSize = MinimumSize
		Size = MinimumSize
		Value = DonemBox.MaxDonem
	End Sub

	Dim _Value As String
	Property Value As String
		Get
			Return _Value
		End Get
		Set(Value As String)
			DonemBox.Normalize(Value)
			_Value = Value
			Invalidate()
		End Set
	End Property

	Protected Overrides Sub OnEnter(e As System.EventArgs)
		MyBase.OnEnter(e)
	End Sub

	Dim Rects As New SortedList(Of String, Rectangle)

	Dim _HoverRect As Rectangle
	Property HoverRect As Rectangle
		Get
			Return _HoverRect
		End Get
		Set(value As Rectangle)
			_HoverRect = value
			If Not value = Rectangle.Empty Then
				Cursor = Cursors.Hand
			Else
				Cursor = Cursors.Default
			End If
			Invalidate()
		End Set
	End Property

	Dim WithEvents Timer As New Timer With {.Interval = 250}

	Protected Overrides Sub OnPaint(e As System.Windows.Forms.PaintEventArgs)
		MyBase.OnPaint(e)
		Rects.Clear()
		Dim Rect As Rectangle = ClientRectangle
		Dim R As Rectangle = New Rectangle(0, 0, Width, th)
		e.Graphics.FillRectangle(Color.Black.Brush, R)
		TextRenderer.DrawText(e.Graphics, Mid(Value, 1, 4), Font, R, Color.White, Color.Transparent, TextFormatFlags.HorizontalCenter + TextFormatFlags.VerticalCenter)
		For i As Integer = 1 To 4
			Dim R1 = New Rectangle(Choose(i, R.Left, R.Left + th, R.Right - 2 * th, R.Right - th), R.Top, th, th)
			R1.Inflate(-1, -1)
			Dim s = Choose(i, "w", "3", "4", "8")
			For j = 1 To If(i = 1 Or i = 4, 2, 1)
				Dim RR = R1
				If i = 1 Or i = 4 Then RR.Offset(If(j = 1, -3, 3), 0)
				TextRenderer.DrawText(e.Graphics, s, New Font("marlett", 9), RR, If(HoverRect = R1, Color.Yellow, Color.White), Color.Transparent, TextFormatFlags.HorizontalCenter + TextFormatFlags.VerticalCenter)
			Next
			Rects.Add("a" & i, R1)
		Next
		R.Offset(R.Width + 1, 0)
		If DonemBox.Isveren Then
			R = New Rectangle(0, th + 1, w * 3, h)
			For y = 0 To 3
				Dim dd = y + 1
				Dim d = Mid(Value, 1, 4) & dd
				e.Graphics.FillRectangle(Color.White.Brush, R)
				If d >= DonemBox.MinDonem And d <= DonemBox.MaxDonem Then
					TextRenderer.DrawText(e.Graphics, dd, Font, R, Color.Black, Color.Transparent, TextFormatFlags.HorizontalCenter + TextFormatFlags.VerticalCenter)
					Rects.Add(d, R)
					If R = HoverRect Then e.Graphics.FillRectangle(SystemColors.Highlight.Opacity(64).Brush, R)
					If Value = d Then e.Graphics.FillRectangle(SystemColors.Highlight.Opacity(128).Brush, R)
				Else
					TextRenderer.DrawText(e.Graphics, dd, Font, R, Color.Black.Lighter(50), Color.Transparent, TextFormatFlags.HorizontalCenter + TextFormatFlags.VerticalCenter)
				End If
				R.Offset(-R.Left, R.Height + 1)
			Next
		Else
			R = New Rectangle(0, th + 1, w, h)
			For y = 0 To 3
				For x = 0 To 2
					Dim ay = y * 3 + x + 1
					Dim d = Mid(Value, 1, 4) & Format(ay, "00")
					e.Graphics.FillRectangle(Color.White.Brush, R)
					If d >= DonemBox.MinDonem And d <= DonemBox.MaxDonem Then
						TextRenderer.DrawText(e.Graphics, Format(ay, "00"), Font, R, Color.Black, Color.Transparent, TextFormatFlags.HorizontalCenter + TextFormatFlags.VerticalCenter)
						Rects.Add(d, R)
						If R = HoverRect Then e.Graphics.FillRectangle(SystemColors.Highlight.Opacity(64).Brush, R)
						If Value = d Then e.Graphics.FillRectangle(SystemColors.Highlight.Opacity(128).Brush, R)
					Else
						TextRenderer.DrawText(e.Graphics, Format(ay, "00"), Font, R, Color.Black.Lighter(50), Color.Transparent, TextFormatFlags.HorizontalCenter + TextFormatFlags.VerticalCenter)
					End If
					R.Offset(R.Width + 1, 0)
				Next
				R.Offset(-R.Left, R.Height + 1)
			Next
		End If
	End Sub

	Protected Overrides Sub OnMouseDown(e As System.Windows.Forms.MouseEventArgs)
		MyBase.OnMouseDown(e)
		If HoverRect = Rectangle.Empty Then Return
		For Each kv As KeyValuePair(Of String, Rectangle) In Rects
			If kv.Value = HoverRect Then
				Dim v = kv.Key
				If v = "a1" Then
					Value = DonemBox.MinDonem
				ElseIf v = "a2" Then
					Value = (New Date(Mid(Value, 1, 4), Mid(Value, 5, 2), 1)).AddYears(-1).YM
				ElseIf v = "a3" Then
					Value = (New Date(Mid(Value, 1, 4), Mid(Value, 5, 2), 1)).AddYears(1).YM
				ElseIf v = "a4" Then
					Value = DonemBox.MaxDonem
				Else
					Value = v
					RaiseEvent DateSelected(Me)
				End If
				Return
			End If
		Next
	End Sub

	Event DateSelected(sender As Object)

	Protected Overrides Sub OnMouseMove(e As System.Windows.Forms.MouseEventArgs)
		MyBase.OnMouseMove(e)
		For Each R As Rectangle In Rects.Values
			If R.Contains(e.Location) Then
				HoverRect = R
				Return
			End If
		Next
		HoverRect = Rectangle.Empty
	End Sub

	Protected Overrides Sub OnMouseLeave(e As System.EventArgs)
		MyBase.OnMouseLeave(e)
		HoverRect = Rectangle.Empty
	End Sub

	Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message, keyData As System.Windows.Forms.Keys) As Boolean
		Dim d As New Date(Mid(Value, 1, 4), Mid(Value, 5, 2), 1)
		If keyData = Keys.Return Then
			RaiseEvent DateSelected(Me)
		ElseIf keyData = Keys.Right Then
			Value = d.AddMonths(+1).YM
			Return True
		ElseIf keyData = Keys.Left Then
			Value = d.AddMonths(-1).YM
			Return True
		ElseIf keyData = Keys.Down Then
			Value = d.AddMonths(+3).YM
			Return True
		ElseIf keyData = Keys.Up Then
			Value = d.AddMonths(-3).YM
			Return True
		ElseIf keyData = Keys.Control + Keys.Right Then
			Value = d.AddYears(1).YM
			Return True
		ElseIf keyData = Keys.Control + Keys.Left Then
			Value = d.AddYears(-1).YM
			Return True
		ElseIf keyData = Keys.Home Then
			Value = DonemBox.MinDonem
			Return True
		ElseIf keyData = Keys.End Then
			Value = DonemBox.MaxDonem
			Return True
		ElseIf keyData = Keys.Add Then
			Value = d.AddMonths(+1).YM
			Return True
		ElseIf keyData = Keys.Subtract Then
			Value = d.AddMonths(-1).YM
			Return True
		End If
		Return MyBase.ProcessCmdKey(msg, keyData)
	End Function

End Class
